using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using Microsoft.ApplicationBlocks.Data;
using System.Xml;
using System.Collections;
using System.Data;

namespace Microsoft.SharedSource.SqlServer.MDDE.Repository
{
    public sealed class InstanceMapping
    {
        #region Fields

        InstanceConfigurableComponent parentComponent;
        string sourceColumnName;
        Boolean sourceColumnUsage;
        string destinationColumnName;

        #endregion

        #region Properties

        public InstanceConfigurableComponent ParentComponent
        {
            get { return parentComponent; }
        }

        public string SourceColumnName
        {
            get { return sourceColumnName; }
        }

        public Boolean SourceColumnUsage
        {
            get { return sourceColumnUsage; }
            set { sourceColumnUsage = value; }
        }

        public string DestinationColumnName
        {
            get { return destinationColumnName; }
            set { destinationColumnName = value; }
        }

        #endregion

        #region Methods

        public InstanceMapping(
            InstanceConfigurableComponent parentComponent,
            string sourceColumnName)
            : this(parentComponent, sourceColumnName, null)
        { }

        public InstanceMapping(
            InstanceConfigurableComponent parentComponent,
            string sourceColumnName, SqlTransaction txn)
        {
            this.parentComponent = parentComponent;
            this.sourceColumnName = sourceColumnName;

            // See if we can get this mapping from repository.
            SqlParameter[] sqlParams = new SqlParameter[2];
            sqlParams[0] = new SqlParameter("componentId",
                parentComponent.Id);
            sqlParams[1] = new SqlParameter("sourceColumnName",
                sourceColumnName);

            DataSet mappingSourceColumns;
            if(txn==null)
                mappingSourceColumns = SqlHelper.ExecuteDataset(
                parentComponent.ParentInstance.ParentTemplate.
                ParentRepository.RepositoryConnection,
                CommandType.Text,
                Resource.GetMappingInfo, sqlParams);
            else
                mappingSourceColumns = SqlHelper.ExecuteDataset(txn,
                CommandType.Text,
                Resource.GetMappingInfo, sqlParams);

            // Return if we find nothing.
            if (mappingSourceColumns.Tables[0].Rows.Count == 0)
                return;
            DataRow r = mappingSourceColumns.Tables[0].Rows[0];
            this.destinationColumnName =
                r["DestinationColumnName"].ToString();

            this.sourceColumnUsage =
                Convert.ToBoolean(
                r["SourceColumnUsage"].ToString());
        }

        internal void Create(SqlTransaction inputTxn)
        {
            // Create a new transaction if there is no input transaction.
            SqlTransaction txn = inputTxn != null ? inputTxn :
                parentComponent.
                ParentInstance.ParentTemplate.ParentRepository.
                RepositoryConnection.BeginTransaction();

            try
            {
                SqlParameter[] sqlParams = new SqlParameter[4];
                sqlParams[0] = new SqlParameter(
                    "componentId", parentComponent.Id);
                sqlParams[1] = new SqlParameter(
                    "sourceColumnName", this.SourceColumnName);
                sqlParams[2] = new SqlParameter(
                    "sourceColumnUsage", this.SourceColumnUsage);
                sqlParams[3] = new SqlParameter(
                    "destinationColumnName", this.DestinationColumnName);

                SqlHelper.ExecuteNonQuery(txn,
                    CommandType.StoredProcedure,
                    "sp_CreateInstanceMapping",
                    sqlParams);

                // Commit the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Commit();
            }
            catch (Exception ex)
            {
                // Rollback the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Rollback();
                throw ex;
            }
        }

        internal void Update(SqlTransaction txn)
        {
            // Update mapping.
            SqlParameter[] sqlParams = new SqlParameter[4];
            sqlParams[0] = new SqlParameter(
                "componentId", parentComponent.Id);
            sqlParams[1] = new SqlParameter(
                "sourceColumnName", this.SourceColumnName);
            sqlParams[2] = new SqlParameter(
                "sourceColumnUsage", this.SourceColumnUsage);
            sqlParams[3] = new SqlParameter(
                "destinationColumnName", this.DestinationColumnName);

            SqlHelper.ExecuteNonQuery(txn,
                CommandType.StoredProcedure,
                "sp_UpdateInstanceMapping",
                sqlParams);
        }

        internal void Delete(SqlTransaction tn)
        {
            // Delete mapping.
            SqlParameter[] sqlParams = new SqlParameter[2];
            sqlParams[0] = new SqlParameter(
                "componentId", parentComponent.Id);
            sqlParams[1] = new SqlParameter(
                "sourceColumnName", this.SourceColumnName);

            SqlHelper.ExecuteNonQuery(tn,
                CommandType.StoredProcedure,
                "sp_DeleteInstanceMapping",
                sqlParams);
        }

        #endregion

        internal void ApplyProperties(XmlNode xMapping)
        {
            this.sourceColumnUsage = 
                Convert.ToBoolean(xMapping.Attributes["Usage"].Value);

            this.destinationColumnName =
                xMapping.Attributes["DestinationColumn"].Value;
        }
    }

    public sealed class InstanceMappingCollection : IEnumerable
    {
        #region Fields

        private Dictionary<string, InstanceMapping>
            instanceMappings =
            new Dictionary<string, InstanceMapping>();
        InstanceConfigurableComponent parentComponent;

        #endregion

        #region Properties

        public int Count
        {
            get { return instanceMappings.Count; }
        }

        public InstanceConfigurableComponent ParentComponent
        {
            get { return parentComponent; }
        }

        public InstanceMapping this[string sourceColumnName]
        {
            get { return instanceMappings[sourceColumnName]; }
        }

        #endregion

        #region Methods

        internal InstanceMappingCollection(
            InstanceConfigurableComponent parentComponent)
        {
            this.parentComponent = parentComponent;
        }

        public void Add(InstanceMapping instanceMapping)
        {
            instanceMappings.Add(
                instanceMapping.SourceColumnName, instanceMapping);
        }

        public void Remove(InstanceMapping instanceMapping)
        {
            instanceMappings.Remove(instanceMapping.SourceColumnName);
        }

        public void Clear()
        {
            instanceMappings.Clear();
        }

        public bool ContainsInstanceMapping(string sourceColumnName)
        {
            return instanceMappings.ContainsKey(sourceColumnName);
        }

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return instanceMappings.Values.GetEnumerator();
        }

        #endregion
    }
}
